package com.ian.controller;

import com.ian.annotation.ContactPermission;
import com.ian.entity.Contact;
//import org.springframework.data.repository.query.Param;
import org.springframework.security.access.method.P;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.acl.Permission;
import java.util.ArrayList;
import java.util.List;

@RestController
public class TestController {

    // test web security: start
    @GetMapping("/hello")
    public String hello() {
        System.out.println("hello");
        return "hello";
    }

    @GetMapping("/hello1")
    public String hello1() {
        System.out.println("hello1");
        return "hello1";
    }

    @GetMapping("/hello2")
    public String hello2() {
        System.out.println("hello2");
        return "hello2";
    }

    @GetMapping("/user")
    public String user() {
        System.out.println("user");
        return "user";
    }

    @GetMapping("/admin")
    public String admin() {
        System.out.println("admin");
        return "admin";
    }
    // test web security: end
    // test method security: start
    /*
    @PreAuthorize, @PostAuthorize
     */
    @PreAuthorize("hasRole('admin')")
    @GetMapping("/create")
    public String create() {
        System.out.println("create");
        return "create";
    }

    @PreAuthorize("hasPermission(#contact, 'admin')")
    @GetMapping("/deletePermission")
    public String deletePermission(Contact contact, Permission permission) {
        System.out.println("deletePermission");
        return "deletePermission";
    }

    // @P annotation is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names.
    @PostMapping("/doSomething")
    @PreAuthorize("#c.name == authentication.name")
    public String doSomething(@P("c") Contact contact) {
        System.out.println("doSomething");
        return "doSomething";
    }

    // @Param annotation is useful for interfaces compiled with a JDK prior to JDK 8 which do not contain any information about the parameter names.
//    @PreAuthorize("#n == authentication.name")
//    @GetMapping("/doSomething")
//    public String findContactByName(@Param("n") String name) {
//        System.out.println("findContactByName");
//        return "findContactByName";
//    }

    @PreAuthorize("#contact.name == authentication.name")
    @PostMapping("/doSomething2")
    public String doSomething2(Contact contact) {
        System.out.println("doSomething2");
        return "doSomething2";
    }

    // @ContactPermission is a meata annotation to supersede @PreAuthorize("#contact.name == authentication.name")
    @ContactPermission
    @PostMapping("/doSomething3")
    public String doSomething3(Contact contact) {
        System.out.println("doSomething3");
        return "doSomething3";
    }

    @PreAuthorize("#contact.name == principle.username")
    @PostMapping("/doSomething4")
    public String doSomething4(Contact contact) {
        System.out.println("doSomething4");
        return "doSomething4";
    }

    @PostAuthorize("#returnObject == 'zhangsan'")
    @GetMapping("/doSomething4")
    public String doSomething4(String name) {
        System.out.println("doSomething4");
        return "doSomething4";
    }

    /*
    @PreFilter,   @PostFilter
    When using the @PostFilter annotation, Spring Security iterates through the returned collection or map and removes any elements
    for which the supplied expression is false. For an array, a new array instance will be returned containing filtered elements.
    The name filterObject refers to the current object in the collection. In case when a map is used it will refer to the current Map.Entry
    object which allows one to use filterObject.key or filterObject.value in the expresion. You can also filter before the method call,
    using @PreFilter, though this is a less common requirement. The syntax is just the same, but if there is more than one argument which
    is a collection type then you have to select one by name using the filterTarget property of this annotation.
     */
    /*
    hasPermission 表达式，目前默认全部是false，也就是说，默认返回给前端的值都是空。
    关于如何使用 hasPermission 表达式，参考该链接：https://blog.csdn.net/xmj_0422/article/details/107971712
     */
    @PreAuthorize("hasRole('user')")
    @PostFilter("hasPermission(filterObject.role, 'read') or hasPermission(filterObject.role, 'admin')")
    @GetMapping("/getAll")
    public List<Contact> getAll() {
        List<Contact> list = new ArrayList<>();
        list.add(new Contact("1", "zhangsan", "read"));
        list.add(new Contact("2", "lisi", "admin"));
        list.add(new Contact("3", "wangwu", "user"));
        return list;
    }


    // test method security: end
}
